﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ОписаниеПеременных

Перем ГенераторСлучайныхЧисел;
Перем ПрограммныйВызов;

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

////////////////////////////////////////////////////////////////////////////////
// Процедуры скрытия конфиденциальной информации в интерактивном режиме.


// Параметры:
//  Параметры - Структура:
//   * ПараметрыОтбора - см. Обработки.СкрытиеКонфиденциальнойИнформации.ПараметрыОтбораУничтожаемыхДанных
//   * ДеревоОбрабатываемыхОбъектов - ДеревоЗначений
//   * ПравилаОбработки - см. Обработки.СкрытиеКонфиденциальнойИнформации.ПравилаОбработкиПоУмолчанию
//  АдресХранилища - Строка
// 
// Возвращаемое значение:
//  ТаблицаЗначений:
//   * ИмяОбъекта - Строка
//   * Поле - Строка
//   * Категория - Строка
//   * ИдентификаторОбъекта - УникальныйИдентификатор
//
Функция УничтожитьПерсональныеДанные(Параметры, АдресХранилища = Неопределено) Экспорт
	
	ГенераторСлучайныхЧисел = Новый ГенераторСлучайныхЧисел;
	ПрограммныйВызов = Ложь;
	
	ПараметрыОтбора = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ПараметрыОтбора",
		Обработки.СкрытиеКонфиденциальнойИнформации.ПараметрыОтбораУничтожаемыхДанных());
		
	Субъекты = ПараметрыОтбора.Субъекты;
	
	ДеревоОбрабатываемыхОбъектов = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры,
		"ДеревоОбрабатываемыхОбъектов",	ЗащитаПерсональныхДанныхУничтожениеПовтИсп.ДеревоОбрабатываемыхОбъектов());
		
	ПравилаОбработки = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры,
		"ПравилаОбработки",	Обработки.СкрытиеКонфиденциальнойИнформации.ПравилаОбработкиПоУмолчанию());
	
	ЗаполнитьЗначенияСвойств(ЭтотОбъект, ПравилаОбработки);
	
	ОчищатьДвоичныеДанныеФайлов = УдалятьФайлы И Не ПроверитьРегистрДляУдаленияФайловВыбран(ДеревоОбрабатываемыхОбъектов);
	ПараметрыОтбора.Вставить("ОчищатьДвоичныеДанныеФайлов", ОчищатьДвоичныеДанныеФайлов);
	
	УстановитьПривилегированныйРежим(Истина);
	
	// Уничтожение ПДн выполняется в два этапа:
	// 1. Уничтожаются ПДн в субъектах.
	// 2. Уничтожаются данные в объектах, содержащих ПДн субъектов.
	
	Если ЗначениеЗаполнено(Субъекты) Тогда
		ИменаМетаданныхСубъектов = ЗащитаПерсональныхДанных.ИменаМетаданныхПоТипамСубъекта();
	Иначе
		ИменаМетаданныхСубъектов = Новый Массив;
	КонецЕсли;
	
	// Уничтожаем ПДн в субъектах.
	Для Каждого ИмяОбъекта Из ИменаМетаданныхСубъектов Цикл
		
		СтрокаДерева = ДеревоОбрабатываемыхОбъектов.Строки.Найти(ИмяОбъекта, "ПолноеИмя", Истина);
		
		Если СтрокаДерева = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если СтрокаДерева.Пометка = 0 Тогда
			Продолжить;
		КонецЕсли;
		
		//@skip-check query-in-loop - порционная обработка большого объема данных
		ОбработатьОбъектМетаданных(СтрокаДерева, ПараметрыОтбора);
		
	КонецЦикла;
	
	// Уничтожаем данные в объектах, содержащих ПДн субъектов.
	Для Каждого ТипМетаданных Из ДеревоОбрабатываемыхОбъектов.Строки Цикл
		
		Если ТипМетаданных.Пометка = 0 Тогда
			Продолжить;
		КонецЕсли;
		
		Для Каждого ОбъектМетаданных Из ТипМетаданных.Строки Цикл
			
			Если ОбъектМетаданных.Пометка = 0 Тогда
				Продолжить;
			КонецЕсли;
			
			Если ИменаМетаданныхСубъектов.Найти(ОбъектМетаданных.ПолноеИмя) <> Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			Если ОбъектМетаданных.Тип = "Константы" Тогда
				ОбработатьКонстанты(ОбъектМетаданных);
				Продолжить;
			КонецЕсли;
			
			Если СтрНайти(ОбъектМетаданных.Тип, "Регистры") > 0 Тогда
				//@skip-check query-in-loop - порционная обработка большого объема данных
				ОбработатьРегистры(ОбъектМетаданных, ПараметрыОтбора);
			Иначе
				//@skip-check query-in-loop - порционная обработка большого объема данных
				ОбработатьОбъектМетаданных(ОбъектМетаданных, ПараметрыОтбора);
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
	ИмяРегистраВерсииОбъектов = "ВерсииОбъектов";
	Если Метаданные.НайтиПоПолномуИмени("РегистрСведений." + ИмяРегистраВерсииОбъектов) <> Неопределено 
		И Не ЗначениеЗаполнено(Субъекты)Тогда
		
		НаборЗаписей = РегистрыСведений[ИмяРегистраВерсииОбъектов].СоздатьНаборЗаписей();
		НаборЗаписей.Записать();
		
	КонецЕсли;
	
	Если ОчищатьПерсональныеНастройкиПользователей Тогда
		ОчиститьПерсональныеНастройкиПользователей();
	КонецЕсли;
	
	Если АдресХранилища <> Неопределено Тогда
		ПоместитьВоВременноеХранилище(Истина, АдресХранилища);
	КонецЕсли;
	
	Возврат УничтоженныеДанные.Выгрузить();
	
КонецФункции

// Параметры:
//   СохраненныеНастройки - Массив из Строка
//   АдресХранилища - Строка
//
Процедура ЗаполнитьДеревоОбрабатываемыхОбъектов(СохраненныеНастройки, АдресХранилища) Экспорт
	
	ДеревоОбрабатываемыхОбъектов = ЗащитаПерсональныхДанныхУничтожениеПовтИсп.ДеревоОбрабатываемыхОбъектовБезНастроек();
	
	ПрименитьНастройкиКДереву(СохраненныеНастройки, ДеревоОбрабатываемыхОбъектов);
	ПоместитьВоВременноеХранилище(ДеревоОбрабатываемыхОбъектов, АдресХранилища);
	
КонецПроцедуры

Процедура ПрименитьНастройкиКДереву(МассивНастроек, ДеревоОбрабатываемыхОбъектов) Экспорт
	
	УстановитьСохраненныеНастройки(МассивНастроек, ДеревоОбрабатываемыхОбъектов);
	Обработки.СкрытиеКонфиденциальнойИнформации.УстановитьНастройкиВДеревеОбрабатываемыхОбъектов(
		ДеревоОбрабатываемыхОбъектов);
	
КонецПроцедуры

Процедура УстановитьСохраненныеНастройки(МассивНастроек, ДеревоОбрабатываемыхОбъектов)
	
	Если МассивНастроек.Количество() = 1 Тогда
		СохраненныеНастройки = ЗначениеИзСтрокиXML(МассивНастроек[0]);
	Иначе
		СохраненныеНастройки = Неопределено;
		ОбъединитьТаблицы(СохраненныеНастройки, МассивНастроек);
	КонецЕсли;
	
	Если СохраненныеНастройки <> Неопределено Тогда
		Для Каждого СохраненнаяНастройка Из СохраненныеНастройки Цикл
			НайденнаяСтрока = ДеревоОбрабатываемыхОбъектов.Строки.Найти(СохраненнаяНастройка.ПолноеИмя, "ПолноеИмя",
				Истина);
			Если НайденнаяСтрока = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			ЗаполнитьЗначенияСвойств(НайденнаяСтрока, СохраненнаяНастройка);
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   ОбъектМетаданных - ОбъектМетаданныхРегистрБухгалтерии
//                    - ОбъектМетаданныхРегистрНакопления
//                    - ОбъектМетаданныхРегистрРасчета
//                    - ОбъектМетаданныхРегистрСведений
//   ПараметрыОтбора - Неопределено
//                   - Структура:
//   * ОсновноеПолеОтбора - Строка
//   * Субъекты - Массив из СправочникСсылка
//
Процедура ОбработатьРегистры(ОбъектМетаданных, ПараметрыОтбора)
	
	Если ОбъектМетаданных.Тип = "РегистрыСведений" Тогда
		Коллекция = РегистрыСведений;
	ИначеЕсли ОбъектМетаданных.Тип = "РегистрыНакопления" Тогда
		Коллекция = РегистрыНакопления;
	ИначеЕсли ОбъектМетаданных.Тип = "РегистрыБухгалтерии" Тогда
		Коллекция = РегистрыБухгалтерии;
	ИначеЕсли ОбъектМетаданных.Тип = "РегистрыРасчета" Тогда
		Коллекция = РегистрыРасчета;
	КонецЕсли;
	
	Регистр = Коллекция[ОбъектМетаданных.Имя];
	НаборЗаписейРегистра = Регистр.СоздатьНаборЗаписей();
	МетаданныеРегистра   = НаборЗаписейРегистра.Метаданные();
		
	Если ОбъектМетаданных.Тип = "РегистрыСведений" Тогда
		РегистрПериодический = (МетаданныеРегистра.ПериодичностьРегистраСведений <>
			Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический);
		РежимЗаписиНезависимый =
			(МетаданныеРегистра.РежимЗаписи = Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.Независимый);
		
		// Периодический и независимый режим записи.
		Если РегистрПериодический И РежимЗаписиНезависимый Тогда
			
			ПараметрыОтбора.ОсновноеПолеОтбора = "Период";
			ОбработатьНаборЗаписейСОтбором(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора);
			
		// Непериодический и режим записи независимый.
		ИначеЕсли РежимЗаписиНезависимый Тогда
			
			КоличествоЗаписей = КоличествоЗаписейРегистра(ОбъектМетаданных.ПолноеИмя);
			
			Если КоличествоЗаписей > 100000 Тогда
				
				ШаблонЗапроса =
					"ВЫБРАТЬ
					|	КОЛИЧЕСТВО(*) КАК Количество
					|ПОМЕСТИТЬ ВтВыборка
					|ИЗ
					|	&ИмяТаблицы КАК Регистр
					|
					|СГРУППИРОВАТЬ ПО
					|	&ИмяИзмерения
					|;
					|ВЫБРАТЬ
					|	КОЛИЧЕСТВО(*) КАК ВышеПорога,
					|	МАКСИМУМ(ВтВыборка.Количество) КАК Максимум,
					|	0 КАК Всего
					|ИЗ
					|	ВтВыборка КАК ВтВыборка
					|ГДЕ
					|	ВтВыборка.Количество > 100000
					|
					|ОБЪЕДИНИТЬ ВСЕ
					|
					|ВЫБРАТЬ
					|	0 КАК ВышеПорога,
					|	0 КАК Максимум,
					|	КОЛИЧЕСТВО(*) КАК Всего
					|ИЗ
					|	ВтВыборка КАК ВтВыборка";
				
				ОписанияИзмерений = Новый ТаблицаЗначений;
				ОписанияИзмерений.Колонки.Добавить("Измерение");
				ОписанияИзмерений.Колонки.Добавить("ВышеПорога");
				ОписанияИзмерений.Колонки.Добавить("Максимум");
				ОписанияИзмерений.Колонки.Добавить("Всего");
				
				ЕстьИзмеренияНижеПорога = Ложь;
				
				Для Каждого Измерение Из МетаданныеРегистра.Измерения Цикл
					
					ТекстЗапроса = СтрЗаменить(ШаблонЗапроса, "&ИмяТаблицы", ОбъектМетаданных.ПолноеИмя);
					ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяИзмерения", "Регистр." + Измерение.Имя);
					Запрос = Новый Запрос(ТекстЗапроса);
					//@skip-check query-in-loop - определение количества записей по каждому измерению
					Результат = Запрос.Выполнить().Выгрузить();
					
					Строка = ОписанияИзмерений.Добавить();
					Строка.Измерение  = Измерение.Имя;
					Строка.ВышеПорога = Результат[0].ВышеПорога;
					Строка.Максимум   = Результат[0].Максимум;
					Строка.Всего      = Результат[1].Всего;
					
					Если Строка.ВышеПорога = 0 Тогда
						ЕстьИзмеренияНижеПорога = Истина;
					КонецЕсли;
					
				КонецЦикла;
				
				Если ЕстьИзмеренияНижеПорога Тогда
					ОписанияИзмерений.Сортировать("ВышеПорога Возр, Всего Возр");
				Иначе
					ОписанияИзмерений.Сортировать("Максимум Возр");
				КонецЕсли;
				
				ПараметрыОтбора.ОсновноеПолеОтбора = ОписанияИзмерений[0].Измерение;
				ОбработатьНаборЗаписейСОтбором(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора);
				
			Иначе
				
				Если ЗначениеЗаполнено(ПараметрыОтбора.Субъекты) Тогда
					ОбработатьНаборЗаписейСОтборомСубъекта(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора);
				Иначе
					ОбработатьНаборЗаписей(НаборЗаписейРегистра, ОбъектМетаданных);
				КонецЕсли;
				
			КонецЕсли;
			
		Иначе
			
			Если ЗначениеЗаполнено(ПараметрыОтбора.Субъекты) Тогда
				ОбработатьНаборЗаписейСОтборомПоНайденнымСсылкам(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора);
			Иначе
				ПараметрыОтбора.ОсновноеПолеОтбора = "Регистратор";
				ОбработатьНаборЗаписейСОтбором(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора);
			КонецЕсли;
			
		КонецЕсли;
		
	Иначе
		// Остальные регистры.
		Если ЗначениеЗаполнено(ПараметрыОтбора.Субъекты) Тогда
			ОбработатьНаборЗаписейСОтборомПоНайденнымСсылкам(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора);
		Иначе
			ПараметрыОтбора.ОсновноеПолеОтбора = "Регистратор";
			ОбработатьНаборЗаписейСОтбором(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

Функция КоличествоЗаписейРегистра(ПолноеИмя)
	
	ТекстЗапроса =
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(*) КАК Количество
		|ИЗ
		|	&ИмяТаблицы КАК Регистр";
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ПолноеИмя);
	Запрос = Новый Запрос(ТекстЗапроса);
	
	Выборка = Запрос.Выполнить().Выбрать();
	Выборка.Следующий();
	
	Возврат Выборка.Количество;
	
КонецФункции

Процедура ОбработатьНаборЗаписейСОтборомПоНайденнымСсылкам(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора)
	
	МетаданныеРегистра = НаборЗаписейРегистра.Метаданные();
	МассивОбъектов = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(МетаданныеРегистра);
	
	Результат = НайтиПоСсылкам(ПараметрыОтбора.Субъекты, Новый Массив, МассивОбъектов, Новый Массив);
	Регистраторы = ОбщегоНазначенияКлиентСервер.СвернутьМассив(Результат.ВыгрузитьКолонку("Данные"));
	
	Для Каждого Регистратор Из Регистраторы Цикл
		
		ПолеОтбора = НаборЗаписейРегистра.Отбор.Регистратор; // ЭлементОтбора
		ПолеОтбора.Установить(Регистратор);
		ОбработатьНаборЗаписей(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора, Истина);
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ОбработатьНаборЗаписейСОтбором(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора)
	
	Субъекты = ПараметрыОтбора.Субъекты;
	ИмяПоляОтбора = ПараметрыОтбора.ОсновноеПолеОтбора;
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ИмяРегистраОбъект.ИмяПоляОтбора КАК ИмяПоляОтбора
	|ИЗ
	|	ПолноеИмяРегистра КАК ИмяРегистраОбъект";
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "ПолноеИмяРегистра", ОбъектМетаданных.ПолноеИмя);
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "ИмяПоляОтбора", ИмяПоляОтбора);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		ЭлементОтбора = НаборЗаписейРегистра.Отбор[ИмяПоляОтбора]; // ЭлементОтбора
		ЭлементОтбора.Установить(Выборка[ИмяПоляОтбора]);
		
		Если ЗначениеЗаполнено(Субъекты) Тогда
			ОбработатьНаборЗаписейСОтборомСубъекта(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора);
		Иначе
			ОбработатьНаборЗаписей(НаборЗаписейРегистра, ОбъектМетаданных);
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ОбработатьНаборЗаписейСОтборомСубъекта(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора)
	
	Субъекты = ПараметрыОтбора.Субъекты;
	ИменаИзмеренийСТипомСубъекта =
		ЗащитаПерсональныхДанных.ИменаРеквизитовИсточникаСодержащихСубъект(ОбъектМетаданных.ПолноеИмя);
	
	Для Каждого ИмяИзмерения Из ИменаИзмеренийСТипомСубъекта Цикл
		
		Для Каждого Субъект Из Субъекты Цикл
			ЭлементОтбора = НаборЗаписейРегистра.Отбор[ИмяИзмерения]; // ЭлементОтбора
			ЭлементОтбора.Установить(Субъект);
			ОбработатьНаборЗаписей(НаборЗаписейРегистра, ОбъектМетаданных, , Истина);
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

// Параметры:
//   НаборЗаписейРегистра - РегистрРасчетаНаборЗаписейИмяРегистраРасчета
//                        - РегистрБухгалтерииНаборЗаписейИмяРегистраБухгалтерии
//                        - РегистрНакопленияНаборЗаписейИмяРегистраНакопления
//                        - РегистрСведенийНаборЗаписейИмяРегистраСведений
//   ОбъектМетаданных - ДеревоЗначений:
//    * Имя - Строка
//   ПараметрыОтбора - Неопределено,Структура:
//    * ОсновноеПолеОтбора - Строка
//    * Субъекты - Массив из СправочникСсылка
//   РегистрироватьНаУзлах - Булево
//
Процедура ОбработатьНаборЗаписей(НаборЗаписейРегистра, ОбъектМетаданных, ПараметрыОтбора = Неопределено,
	РегистрироватьНаУзлах = Ложь)
	
	НаборЗаписейРегистра.Прочитать();
	
	Если ЗначениеЗаполнено(ПараметрыОтбора) Тогда
		Субъекты = ПараметрыОтбора.Субъекты;
		ИменаИзмеренийСТипомСубъекта = ЗащитаПерсональныхДанных.ИменаРеквизитовИсточникаСодержащихСубъект(
			ОбъектМетаданных.ПолноеИмя);
		ОбрабатыватьЗаписьПриНаличииСубъекта = ЗначениеЗаполнено(ИменаИзмеренийСТипомСубъекта);
	Иначе
		ОбрабатыватьЗаписьПриНаличииСубъекта = Ложь;
		ИменаИзмеренийСТипомСубъекта = Новый Массив;
		Субъекты = Неопределено;
	КонецЕсли;
	
	Обработано = Истина;
	ВыполнитьЗаписьОбъекта = Ложь;
	Для Каждого ЗаписьРегистра Из НаборЗаписейРегистра Цикл
		
		ИдентификаторЗаписи = Новый УникальныйИдентификатор();
		
		Если ЗначениеЗаполнено(Субъекты) Тогда
			
			Если ОбрабатыватьЗаписьПриНаличииСубъекта Тогда
				
				СубъектВЗаписи = Ложь;
				Для Каждого ИмяИзмерения Из ИменаИзмеренийСТипомСубъекта Цикл
					ТекущийСубъект = ЗаписьРегистра[ИмяИзмерения];
					Если Субъекты.Найти(ТекущийСубъект) <> Неопределено Тогда
						СубъектВЗаписи = Истина;
						Прервать;
					КонецЕсли;
				КонецЦикла;
				
				Если Не СубъектВЗаписи Тогда
					Продолжить;
				КонецЕсли;
				
			Иначе
				Продолжить;
			КонецЕсли;
			
		КонецЕсли;
			
		Для Каждого ГруппаСвойствОбъекта Из ОбъектМетаданных.Строки Цикл
			
			Если ГруппаСвойствОбъекта.Пометка = 0 Тогда
				Продолжить;
			КонецЕсли;
			
			Для Каждого ОбрабатываемоеСвойство Из ГруппаСвойствОбъекта.Строки Цикл
				Если ОбрабатываемоеСвойство.Пометка = 0 Тогда
					Продолжить;
				КонецЕсли;
				
				Если ОбъектМетаданных.Тип = "РегистрыБухгалтерии" И ОбрабатываемоеСвойство.Тип = "Ресурсы" Тогда
					ЗначениеДт = ЗаписьРегистра[ОбрабатываемоеСвойство.Имя + "Дт"];
					ЗначениеДт = ?(ТипЗнч(ЗначениеДт) = Тип("Число"), ЗначениеДт, 0);
					ЗначениеКт = ЗаписьРегистра[ОбрабатываемоеСвойство.Имя + "Кт"];
					ЗначениеКт = ?(ТипЗнч(ЗначениеКт) = Тип("Число"), ЗначениеКт, 0);
					ОбработатьСвойство(ЗначениеДт, ОбрабатываемоеСвойство, Обработано);
					ОбработатьСвойство(ЗначениеКт, ОбрабатываемоеСвойство, Обработано);
					Если Обработано Тогда
						ЗаписьРегистра[ОбрабатываемоеСвойство.Имя + "Дт"] = ЗначениеДт;
						ЗаписьРегистра[ОбрабатываемоеСвойство.Имя + "Кт"] = ЗначениеКт;
						ДобавитьУничтоженныеДанные(ОбъектМетаданных.ПолноеИмя, ОбрабатываемоеСвойство.Имя + "Дт",
							ОбрабатываемоеСвойство.КатегорияДанных, ИдентификаторЗаписи);
						ДобавитьУничтоженныеДанные(ОбъектМетаданных.ПолноеИмя, ОбрабатываемоеСвойство.Имя + "Кт",
							ОбрабатываемоеСвойство.КатегорияДанных, ИдентификаторЗаписи);
					КонецЕсли;
				Иначе
					Значение = ЗаписьРегистра[ОбрабатываемоеСвойство.Имя];
					ОбработатьСвойство(Значение, ОбрабатываемоеСвойство, Обработано);
					Если Обработано Тогда
						ЗаписьРегистра[ОбрабатываемоеСвойство.Имя] = Значение;
						ДобавитьУничтоженныеДанные(ОбъектМетаданных.ПолноеИмя, ОбрабатываемоеСвойство.Имя,
							ОбрабатываемоеСвойство.КатегорияДанных, ИдентификаторЗаписи);
					КонецЕсли;
				КонецЕсли;
				
				ВыполнитьЗаписьОбъекта = ВыполнитьЗаписьОбъекта Или Обработано;
			КонецЦикла;
			
		КонецЦикла;
		
	КонецЦикла;
	
	Если ВыполнитьЗаписьОбъекта Тогда
		ЗаписатьДанные(НаборЗаписейРегистра, РегистрироватьНаУзлах);
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   СтрокаДереваМетаданных - СтрокаДереваЗначений:
//     * ПолноеИмя - Строка
//   ПараметрыОтбора - Неопределено,Структура:
//     * ОсновноеПолеОтбора - Строка
//     * Субъекты - Массив из ОпределяемыйТип.СубъектПерсональныхДанных
//
Процедура ОбработатьОбъектМетаданных(СтрокаДереваМетаданных, ПараметрыОтбора)
	
	ОбработкаПорциями = Ложь;
	Субъекты = ПараметрыОтбора.Субъекты;
	ВключеноВерсионирование = Ложь;
	ИмяОбъекта = СтрокаДереваМетаданных.ПолноеИмя;
	
	Если ЗначениеЗаполнено(Субъекты) Тогда
		МассивОбъектов = НайтиОбъектыПоСсылкам(Субъекты, СтрокаДереваМетаданных);
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВерсионированиеОбъектов") Тогда
			МодульВерсионированиеОбъектов = ОбщегоНазначения.ОбщийМодуль("ВерсионированиеОбъектов");
			ВключеноВерсионирование = МодульВерсионированиеОбъектов.ВключеноВерсионированиеОбъекта(ИмяОбъекта);
		КонецЕсли;
	Иначе
		ОбработкаПорциями = Истина;
		МассивОбъектов = ДанныеОбъектаМетаданных(ИмяОбъекта);
	КонецЕсли;
	
	ОбрабатываемыйОбъект = Неопределено;
	Пока Истина Цикл
		
		Если МассивОбъектов.Количество() = 0 Тогда
			Прервать;
		КонецЕсли;
		
		Для Каждого СсылкаНаОбъект Из МассивОбъектов Цикл
			
			Обработано = Истина;
			ВыполнитьЗаписьОбъекта = Ложь;
			
			ЕстьСубъектыВТЧастях = Ложь;
			ЕстьСубъектВРеквизитах = Ложь;
			
			ИменаРеквизитовТабличныхЧастей = Новый Соответствие;
			
			ОбрабатываемыйОбъект = СсылкаНаОбъект.ПолучитьОбъект();
			
			Если ЗначениеЗаполнено(Субъекты) Тогда
				
				Параметры = Новый Структура;
				Параметры.Вставить("Субъекты", Субъекты);
				Параметры.Вставить("ИмяОбъекта", ИмяОбъекта);
				Параметры.Вставить("ОбрабатываемыйОбъект", ОбрабатываемыйОбъект);
				
				ОпределитьНаличиеСубъектаВРеквизитахОбъекта(ЕстьСубъектВРеквизитах, ЕстьСубъектыВТЧастях,
					ИменаРеквизитовТабличныхЧастей, Параметры);
				
			КонецЕсли;
			
			Для Каждого ГруппаСвойствОбъекта Из СтрокаДереваМетаданных.Строки Цикл
				
				Если ГруппаСвойствОбъекта.Пометка = 0 Тогда
					Продолжить;
				КонецЕсли;
				
				Для Каждого ОбрабатываемоеСвойство Из ГруппаСвойствОбъекта.Строки Цикл
					
					Если ОбрабатываемоеСвойство.Пометка = 0 Тогда
						Продолжить;
					КонецЕсли;
					
					Если ГруппаСвойствОбъекта.Тип = "ТабличнаяЧасть" Тогда
						
						ПараметрыОбработкиТЧ = Новый Структура;
						ПараметрыОбработкиТЧ.Вставить("Субъекты", Субъекты);
						ПараметрыОбработкиТЧ.Вставить("ИмяОбъекта", ИмяОбъекта);
						ПараметрыОбработкиТЧ.Вставить("ЕстьСубъектВРеквизитах", ЕстьСубъектВРеквизитах);
						ПараметрыОбработкиТЧ.Вставить("ЕстьСубъектыВТЧастях", ЕстьСубъектыВТЧастях);
						ПараметрыОбработкиТЧ.Вставить("ИменаРеквизитовТабличныхЧастей", ИменаРеквизитовТабличныхЧастей);
						ПараметрыОбработкиТЧ.Вставить("ГруппаСвойствОбъекта", ГруппаСвойствОбъекта);
						ПараметрыОбработкиТЧ.Вставить("ОбрабатываемоеСвойство", ОбрабатываемоеСвойство);
						
						ОбработатьТабличнуюЧасть(ОбрабатываемыйОбъект, Обработано, ВыполнитьЗаписьОбъекта,
							ПараметрыОбработкиТЧ);
						
					Иначе
						
						Если ЗначениеЗаполнено(Субъекты) И Не ЕстьСубъектВРеквизитах И Не ЕстьСубъектыВТЧастях Тогда 
							Продолжить;
						КонецЕсли;
						
						Значение = ОбрабатываемыйОбъект[ОбрабатываемоеСвойство.Имя];
						
						ОбработатьСвойство(Значение, ОбрабатываемоеСвойство, Обработано);
						Если Обработано Тогда
							ОбрабатываемыйОбъект[ОбрабатываемоеСвойство.Имя] = Значение;
							ДобавитьУничтоженныеДанные(ИмяОбъекта, ОбрабатываемоеСвойство.Имя,
								ОбрабатываемоеСвойство.КатегорияДанных,
								ОбрабатываемыйОбъект.Ссылка.УникальныйИдентификатор());
						КонецЕсли;
						
						ВыполнитьЗаписьОбъекта = ВыполнитьЗаписьОбъекта Или Обработано;
						
					КонецЕсли;
					
				КонецЦикла;
				
			КонецЦикла;
			
			ЗащитаПерсональныхДанных.ПередУничтожениемПерсональныхДанных(ОбрабатываемыйОбъект, Субъекты,
				ВыполнитьЗаписьОбъекта);
			
			Если ВыполнитьЗаписьОбъекта Тогда
				ВыполнитьЗаписьОбъекта(ОбрабатываемыйОбъект, Субъекты, ПараметрыОтбора.ОчищатьДвоичныеДанныеФайлов,
					ВключеноВерсионирование);
				ЗащитаПерсональныхДанных.ПослеУничтоженияПерсональныхДанных(ОбрабатываемыйОбъект, Субъекты);
			КонецЕсли;
			
		КонецЦикла;
		
		Если ОбработкаПорциями Тогда
			МассивОбъектов = ДанныеОбъектаМетаданных(ИмяОбъекта, СсылкаНаОбъект);
		Иначе
			МассивОбъектов.Очистить();
		КонецЕсли;
		
	КонецЦикла;
	
	Если УдалятьФайлы Тогда
		УдалитьФайлыОбъектаМетаданных(ОбрабатываемыйОбъект, СтрокаДереваМетаданных, ПараметрыОтбора);
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьЗаписьОбъекта(ОбрабатываемыйОбъект, Субъекты, ОчищатьДвоичныеДанныеФайлов, ВключеноВерсионирование)
	
	ЗаписатьДанные(ОбрабатываемыйОбъект, ЗначениеЗаполнено(Субъекты));
	Если ОчищатьДвоичныеДанныеФайлов Тогда
		УдалитьДвоичныеДанныеФайловОбъекта(ОбрабатываемыйОбъект);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Субъекты) И ВключеноВерсионирование Тогда
		ИмяРегистраВерсииОбъектов = "ВерсииОбъектов";
		НаборЗаписей = РегистрыСведений[ИмяРегистраВерсииОбъектов].СоздатьНаборЗаписей();
		ЭлементОтбора = НаборЗаписей.Отбор.Объект; // ЭлементОтбора
		ЭлементОтбора.Установить(ОбрабатываемыйОбъект.Ссылка);
		ЗаписатьДанные(НаборЗаписей, Истина);
	КонецЕсли;
	
КонецПроцедуры

Процедура ОпределитьНаличиеСубъектаВРеквизитахОбъекта(ЕстьСубъектВРеквизитах, ЕстьСубъектыВТЧастях,
	ИменаРеквизитовТабличныхЧастей, Параметры)
	
	ИменаРеквизитовСодержащихСубъект =
		ЗащитаПерсональныхДанных.ИменаРеквизитовИсточникаСодержащихСубъект(Параметры.ИмяОбъекта);
	
	Для Каждого ИмяРеквизита Из ИменаРеквизитовСодержащихСубъект Цикл
		
		ЧастиИмени = СтрРазделить(ИмяРеквизита, ".", Ложь);
		Если ЧастиИмени.Количество() > 1 Тогда
			
			ИмяТЧасти = ЧастиИмени[0];
			ИмяРеквизитаТЧ = ЧастиИмени[1];
			ИменаРеквизитовТЧасти = ИменаРеквизитовТабличныхЧастей.Получить(ИмяТЧасти);
			
			Если ИменаРеквизитовТЧасти = Неопределено Тогда
				ИменаРеквизитовТЧасти = Новый Массив;
			КонецЕсли;
			
			ИменаРеквизитовТЧасти.Добавить(ИмяРеквизитаТЧ);
			ИменаРеквизитовТабличныхЧастей.Вставить(ИмяТЧасти, ИменаРеквизитовТЧасти);
			
		Иначе
			ЕстьСубъектВРеквизитах = ЕстьСубъектВРеквизитах
				Или (Параметры.Субъекты.Найти(Параметры.ОбрабатываемыйОбъект[ИмяРеквизита]) <> Неопределено);
		КонецЕсли;
		
	КонецЦикла;
	
	ЕстьСубъектыВТЧастях = ИменаРеквизитовТабличныхЧастей.Количество() > 0;
	
КонецПроцедуры

Процедура ОбработатьТабличнуюЧасть(ОбрабатываемыйОбъект, Обработано, ВыполнитьЗаписьОбъекта, Параметры)
	
	Субъекты = Параметры.Субъекты;
	ОбрабатываемыеСвойства = ОбрабатываемыйОбъект[Параметры.ГруппаСвойствОбъекта.Имя];
	
	ОбрабатыватьТЧПриНаличииСубъекта = Ложь;
	ИменаРеквизитовТЧСТипомСубъекта = Параметры.ИменаРеквизитовТабличныхЧастей.Получить(Параметры.ГруппаСвойствОбъекта.Имя);
	
	Если ЗначениеЗаполнено(Субъекты) И Параметры.ЕстьСубъектыВТЧастях Тогда
		ОбрабатыватьТЧПриНаличииСубъекта = ЗначениеЗаполнено(ИменаРеквизитовТЧСТипомСубъекта);
	КонецЕсли;
	
	Для Каждого СтрокаТабличнойЧасти Из ОбрабатываемыеСвойства Цикл
		
		Если ЗначениеЗаполнено(Субъекты) Тогда 
			
			Если ОбрабатыватьТЧПриНаличииСубъекта Тогда
				
				СубъектВСтроке = Ложь;
				Для Каждого ИмяРеквизита Из ИменаРеквизитовТЧСТипомСубъекта Цикл
					
					ТекущийСубъект = СтрокаТабличнойЧасти[ИмяРеквизита];
					Если Субъекты.Найти(ТекущийСубъект) <> Неопределено Тогда
						СубъектВСтроке = Истина;
						Прервать;
					КонецЕсли;
					
				КонецЦикла;
				
				Если Не СубъектВСтроке Тогда
					Продолжить;
				КонецЕсли;
				
			ИначеЕсли Параметры.ЕстьСубъектыВТЧастях Или Не Параметры.ЕстьСубъектВРеквизитах Тогда
				Продолжить;
			КонецЕсли;
			
		КонецЕсли;
		
		Значение = СтрокаТабличнойЧасти[Параметры.ОбрабатываемоеСвойство.Имя];
		
		СтандартнаяОбработка = Истина;
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
			ПолноеИмя = Параметры.ОбрабатываемоеСвойство.ПолноеИмя;
			МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль(
				"УправлениеКонтактнойИнформацией");
			МодульУправлениеКонтактнойИнформацией.ПриСкрытииЗначенияРеквизита(ПолноеИмя, Значение,
				СтандартнаяОбработка);
		КонецЕсли;
		
		Если СтандартнаяОбработка Тогда
			ОбработатьСвойство(Значение, Параметры.ОбрабатываемоеСвойство, Обработано);
		Иначе
			Обработано = Истина;
		КонецЕсли;
		
		Если Обработано Тогда
			СтрокаТабличнойЧасти[Параметры.ОбрабатываемоеСвойство.Имя] = Значение;
			ДобавитьУничтоженныеДанные(Параметры.ИмяОбъекта, Параметры.ОбрабатываемоеСвойство.Имя,
				Параметры.ОбрабатываемоеСвойство.КатегорияДанных,
				ОбрабатываемыйОбъект.Ссылка.УникальныйИдентификатор());
		КонецЕсли;
		
		ВыполнитьЗаписьОбъекта = ВыполнитьЗаписьОбъекта Или Обработано;
		
	КонецЦикла;
	
КонецПроцедуры

// Параметры:
//  Субъекты - Массив из ОпределяемыйТип.СубъектПерсональныхДанных
//  СтрокаДерева - СтрокаДереваЗначений:
//   * ПолноеИмя - Строка
// 
// Возвращаемое значение:
//  Массив из СправочникСсылка, ДокументСсылка
//
Функция НайтиОбъектыПоСсылкам(Субъекты, СтрокаДерева)
	
	ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(СтрокаДерева.ПолноеИмя);
	
	НайденныеОбъекты = НайтиПоСсылкам(Субъекты, Новый Массив,
		ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ОбъектМетаданных), Новый Массив);
	НайденныеОбъекты.Свернуть("Данные");
	
	Результат = НайденныеОбъекты.ВыгрузитьКолонку("Данные");
	
	Если Результат.Количество() = 0 Тогда
		Для Каждого Субъект Из Субъекты Цикл
			Если Субъект.Метаданные() = ОбъектМетаданных Тогда
				Результат.Добавить(Субъект);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Добавляет информацию об уничтоженных данных в табличную часть УничтоженныеДанные.
// 
// Параметры:
//  ИмяОбъекта - Строка
//  Поле - Строка
//  Категория - Строка
//  ИдентификаторОбъекта - УникальныйИдентификатор
//
Процедура ДобавитьУничтоженныеДанные(ИмяОбъекта, Поле, Категория, ИдентификаторОбъекта)
	
	НоваяСтрока = УничтоженныеДанные.Добавить();
	НоваяСтрока.ИмяОбъекта = ИмяОбъекта;
	НоваяСтрока.Поле = Поле;
	НоваяСтрока.Категория = Категория;
	НоваяСтрока.ИдентификаторОбъекта = ИдентификаторОбъекта;
	
КонецПроцедуры

// Параметры:
//  ИмяОбъекта - Строка
//  ТекущаяСсылка - СправочникСсылка, ДокументСсылка, Строка
// 
// Возвращаемое значение:
//  Массив из СправочникСсылка, ДокументСсылка
//
Функция ДанныеОбъектаМетаданных(ИмяОбъекта, ТекущаяСсылка = "")
	
	ТекстЗапроса =
		"ВЫБРАТЬ ПЕРВЫЕ 1000
		|	ОбъектМетаданных.Ссылка
		|ИЗ
		|	&ИмяТаблицы КАК ОбъектМетаданных
		|ГДЕ
		|	ОбъектМетаданных.Ссылка > &Ссылка
		|УПОРЯДОЧИТЬ ПО
		|	ОбъектМетаданных.Ссылка";
		
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ИмяОбъекта);

	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Ссылка", ТекущаяСсылка);
	Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
	
КонецФункции

Процедура УдалитьФайлыОбъектаМетаданных(ВладелецФайла, ОбъектМетаданных, ПараметрыОтбора)
	
	Если ВладелецФайла = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если СтрЗаканчиваетсяНа(ОбъектМетаданных.Имя, "ПрисоединенныеФайлы") Тогда
		Возврат;
	КонецЕсли;
	
	МодульРаботаСФайламиСлужебный = ОбщийМодуль("РаботаСФайламиСлужебный");
	Если МодульРаботаСФайламиСлужебный = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ИмяСправочникаХранилищаФайлов = МодульРаботаСФайламиСлужебный.ИмяСправочникаХраненияФайлов(ВладелецФайла);
	Если ПустаяСтрока(ИмяСправочникаХранилищаФайлов) Тогда
		Возврат;
	КонецЕсли;
	
	ПолноеИмяСправочника = "Справочник." + ИмяСправочникаХранилищаФайлов;
	
	ДеревоОбрабатываемыхОбъектов = ОбъектМетаданных.Владелец();
	
	СтруктураПоиска = Новый Структура;
	СтруктураПоиска.Вставить("ПолноеИмя", ПолноеИмяСправочника);
	
	МассивСтрок = ДеревоОбрабатываемыхОбъектов.Строки.НайтиСтроки(СтруктураПоиска, Истина);
	Если МассивСтрок.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	СтрокаСправочникаФайлов = МассивСтрок[0];
	Если СтрокаСправочникаФайлов.Пометка = 1 Тогда
		Возврат;
	КонецЕсли;
	
	УстановитьПометкуДляСтрокДерева(СтрокаСправочникаФайлов.Строки, 1);
	
	ОбработатьОбъектМетаданных(СтрокаСправочникаФайлов, ПараметрыОтбора);
	
КонецПроцедуры

Процедура УстановитьПометкуДляСтрокДерева(КоллекцияСтрок, Пометка)
	
	Для Каждого Строка Из КоллекцияСтрок Цикл
		Строка.Пометка = Пометка;
		УстановитьПометкуДляСтрокДерева(Строка.Строки, Пометка)
	КонецЦикла;
	
КонецПроцедуры

Функция ПроверитьРегистрДляУдаленияФайловВыбран(ДеревоОбрабатываемыхОбъектов)
	
	ИмяРегистраДвоичныхДанных = "ДвоичныеДанныеФайлов";
	Если Метаданные.НайтиПоПолномуИмени("РегистрСведений." + ИмяРегистраДвоичныхДанных) = Неопределено Тогда
		Возврат Истина;
	КонецЕсли;
	
	СтруктураПоиска = Новый Структура;
	СтруктураПоиска.Вставить("ПолноеИмя", "РегистрСведений." + ИмяРегистраДвоичныхДанных);
	
	МассивСтрок = ДеревоОбрабатываемыхОбъектов.Строки.НайтиСтроки(СтруктураПоиска, Истина);
	Если МассивСтрок.Количество() = 0 Тогда
		Возврат Ложь;
	КонецЕсли;
	
	СтрокаРегистра = МассивСтрок[0];
	Возврат (СтрокаРегистра.Пометка = 1);
	
КонецФункции

Процедура УдалитьДвоичныеДанныеФайловОбъекта(ОбрабатываемыйОбъект)
	
	Если НЕ СтрЗаканчиваетсяНа(ОбрабатываемыйОбъект.Метаданные().Имя, "ПрисоединенныеФайлы") Тогда
		Возврат;
	КонецЕсли;
	
	ИмяРегистраДвоичныхДанных = "ДвоичныеДанныеФайлов";
	Если Метаданные.НайтиПоПолномуИмени("РегистрСведений." + ИмяРегистраДвоичныхДанных) = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	НаборЗаписей = РегистрыСведений[ИмяРегистраДвоичныхДанных].СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.Файл.Установить(ОбрабатываемыйОбъект.Ссылка);
	НаборЗаписей.Прочитать();
	
	ВыполнитьЗаписьОбъекта = Ложь;
	Для Каждого Запись Из НаборЗаписей Цикл
		Запись.ДвоичныеДанныеФайла = Неопределено;
		ВыполнитьЗаписьОбъекта = Истина;
	КонецЦикла;
	
	Если ВыполнитьЗаписьОбъекта Тогда
		ЗаписатьДанные(НаборЗаписей);
	КонецЕсли;
	
КонецПроцедуры

Процедура ОчиститьПерсональныеНастройкиПользователей()
	
	ХранилищеПользовательскихНастроекОтчетов.Удалить(Неопределено, Неопределено, Неопределено);
	ХранилищеСистемныхНастроек.Удалить(Неопределено, Неопределено, Неопределено);
	ХранилищеНастроекДанныхФорм.Удалить(Неопределено, Неопределено, Неопределено);
	ХранилищеОбщихНастроек.Удалить(Неопределено, Неопределено, Неопределено);
	
КонецПроцедуры

Процедура ОбъединитьТаблицы(ТаблицаПриемник, МассивНастроек)
	
	Для Каждого СтрокаНастроек Из МассивНастроек Цикл
		ТаблицаНастроек = ЗначениеИзСтрокиXML(СтрокаНастроек);
		Если ТаблицаПриемник = Неопределено Тогда
			ТаблицаПриемник = ТаблицаНастроек.Скопировать();
		Иначе
			Для Каждого СтрокаТаблицы Из ТаблицаНастроек Цикл
				Если ТаблицаПриемник.Найти(СтрокаТаблицы.ПолноеИмя, "ПолноеИмя") = Неопределено Тогда
					ЗаполнитьЗначенияСвойств(ТаблицаПриемник.Добавить(), СтрокаТаблицы);
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция ЗначениеИзСтрокиXML(СтрокаXML)
	
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(СтрокаXML);
	
	Возврат СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Прочие процедуры и функции.

// Параметры:
//  ОбъектМетаданных - ОбъектМетаданныхКонстанта
//
Процедура ОбработатьКонстанты(ОбъектМетаданных)
	
	ЗначениеКонстанты = Константы[ОбъектМетаданных.Имя].Получить();
	МенеджерКонстанты = Константы[ОбъектМетаданных.Имя].СоздатьМенеджерЗначения();
	Обработано = Истина;
	ОбработатьСвойство(ЗначениеКонстанты, ОбъектМетаданных, Обработано);
	
	Если Обработано Тогда
		МенеджерКонстанты.Значение = ЗначениеКонстанты;
		УстановитьПривилегированныйРежим(Истина);
		ЗаписатьДанные(МенеджерКонстанты);
		УстановитьПривилегированныйРежим(Ложь);
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбработатьСвойство(Свойство, ПараметрыСвойства, Обработано)
	
	Если Не ЗначениеЗаполнено(Свойство) Тогда
		Обработано = Ложь;
		Возврат;
	КонецЕсли;
	
	Обработано = Истина;
	ТипСвойства = ТипЗнч(Свойство);
	Если ТипСвойства = Тип("Строка") Тогда
		ОбработатьСтроку(Свойство, ПараметрыСвойства, Обработано);
	ИначеЕсли ТипСвойства = Тип("Число") Тогда
		ОбработатьЧисло(Свойство, ПараметрыСвойства, Обработано);
	ИначеЕсли ТипСвойства = Тип("Булево") Тогда
		ОбработатьБулево(Свойство, ПараметрыСвойства, Обработано);
	ИначеЕсли ТипСвойства = Тип("Дата") Тогда
		ОбработатьДату(Свойство, ПараметрыСвойства, Обработано);
	ИначеЕсли ТипСвойства = Тип("ХранилищеЗначения") Тогда
		ОбработатьХранилищеЗначений(Свойство, ПараметрыСвойства, Обработано);
	Иначе
		Обработано = Ложь;
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбработатьСтроку(Свойство, ПараметрыСвойства, Обработано)
	
	Индекс = XMLСтрока(ГенераторСлучайныхЧисел.СлучайноеЧисло(100000, 999999));
	
	ПравилоОбработки = ПравилоСтрока;
	Если ПараметрыСвойства.ПравилоОбработки.Количество() > 0 Тогда
		ПараметрыОбработкиСтроки = ПараметрыСвойства.ПравилоОбработки.НайтиПоЗначению("Строка");
		Если ПараметрыОбработкиСтроки <> Неопределено Тогда
			ПравилоОбработки = ПараметрыОбработкиСтроки.Представление;
		КонецЕсли;
	КонецЕсли;
	
	Если ПрограммныйВызов И ПараметрыСвойства.Имя = "Наименование" Тогда
		ПравилоОбработки = "ИмяОбъектаИндекс";
	КонецЕсли;
	
	Если ПравилоОбработки = "Очистить" Тогда
		Если ПараметрыСвойства.ПроверкаЗаполнения = ПроверкаЗаполнения.ВыдаватьОшибку Тогда
			Свойство = СтрЗаменить(Новый УникальныйИдентификатор, "-", "");
		Иначе
			Свойство = "";
		КонецЕсли;
	ИначеЕсли ПравилоОбработки = "СлучайноеЗначение" Тогда
		Свойство = СтрЗаменить(Новый УникальныйИдентификатор, "-", "");
	ИначеЕсли ПравилоОбработки = "ИмяПоляИндекс" Тогда
		Свойство = ПараметрыСвойства.Имя + Индекс;
	ИначеЕсли ПравилоОбработки = "ИмяОбъектаИндекс" Тогда
		ИмяОбъекта = СтрРазделить(ПараметрыСвойства.ПолноеИмя, ".")[1];
		Свойство = ИмяОбъекта + Индекс;
	Иначе
		Обработано = Ложь;
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбработатьЧисло(Свойство, ПараметрыСвойства, Обработано)
	
	ПравилоОбработки = ПравилоЧисло;
	Если ПараметрыСвойства.ПравилоОбработки.Количество() > 0 Тогда
		ПараметрыОбработкиЧисел = ПараметрыСвойства.ПравилоОбработки.НайтиПоЗначению("Число");
		Если ПараметрыОбработкиЧисел <> Неопределено Тогда
			ПравилоОбработки = ПараметрыОбработкиЧисел.Представление;
		КонецЕсли;
	КонецЕсли;
	
	Если ПравилоОбработки = "Очистить" Тогда
		Свойство = 0;
	ИначеЕсли СтрНайти(ПравилоОбработки, "Умножить") > 0 Тогда
		ПравилоМассив = СтрРазделить(ПравилоОбработки, ";");
		Свойство = Свойство * Число(ПравилоМассив[1]);
	ИначеЕсли СтрНайти(ПравилоОбработки, "Разделить") > 0 Тогда
		ПравилоМассив = СтрРазделить(ПравилоОбработки, ";");
		Свойство = Свойство / Число(ПравилоМассив[1]);
	ИначеЕсли СтрНайти(ПравилоОбработки, "Прибавить") > 0 Тогда
		ПравилоМассив = СтрРазделить(ПравилоОбработки, ";");
		Свойство = Свойство + Число(ПравилоМассив[1]);
	ИначеЕсли СтрНайти(ПравилоОбработки, "Вычесть") > 0 Тогда
		ПравилоМассив = СтрРазделить(ПравилоОбработки, ";");
		Свойство = Свойство - Число(ПравилоМассив[1]);
	ИначеЕсли СтрНайти(ПравилоОбработки, "СлучайноеЗначение") > 0 Тогда
		Свойство = ГенераторСлучайныхЧисел.СлучайноеЧисло(1, 1000000);
	Иначе
		Обработано = Ложь;
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбработатьБулево(Свойство, ПараметрыСвойства, Обработано)
	
	ПравилоОбработки = ПравилоБулево;
	Если ПараметрыСвойства.ПравилоОбработки.Количество() > 0 Тогда
		ПараметрыОбработкиБулево = ПараметрыСвойства.ПравилоОбработки.НайтиПоЗначению("Булево");
		Если ПараметрыОбработкиБулево <> Неопределено Тогда
			ПравилоОбработки = ПараметрыОбработкиБулево.Представление;
		КонецЕсли;
	КонецЕсли;
	
	Если ПравилоОбработки = "Инвертировать" Тогда
		Свойство = Не Свойство;
	Иначе
		Обработано = Ложь;
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбработатьДату(Свойство, ПараметрыСвойства, Обработано)
	
	ПравилоОбработки = ПравилоДата;
	Если ПараметрыСвойства.ПравилоОбработки.Количество() > 0 Тогда
		ПараметрыОбработкиДат = ПараметрыСвойства.ПравилоОбработки.НайтиПоЗначению("Булево");
		Если ПараметрыОбработкиДат <> Неопределено Тогда
			ПравилоОбработки = ПараметрыОбработкиДат.Представление;
		КонецЕсли;
	КонецЕсли;
	
	Если ПрограммныйВызов = Истина Тогда
		Свойство = Неопределено;
		Возврат;
	КонецЕсли;
	
	СуткиВСекундах = 60 * 60 * 24;
	
	Если ПравилоОбработки = "Очистить" И ПараметрыСвойства.ПроверкаЗаполнения = ПроверкаЗаполнения.ВыдаватьОшибку Тогда
		ПравилоОбработки = "СлучайноеЗначение";
	КонецЕсли;
	
	Если ПравилоОбработки = "Очистить" Тогда
		Свойство = Дата(1, 1, 1);
	ИначеЕсли СтрНайти(ПравилоОбработки, "Прибавить") > 0 Тогда
		ПравилоМассив = СтрРазделить(ПравилоОбработки, ";");
		Свойство = Свойство + СуткиВСекундах * Число(ПравилоМассив[1]);
	ИначеЕсли СтрНайти(ПравилоОбработки, "Вычесть") > 0 Тогда
		ПравилоМассив = СтрРазделить(ПравилоОбработки, ";");
		Свойство = Свойство - СуткиВСекундах * Число(ПравилоМассив[1]);
	ИначеЕсли СтрНайти(ПравилоОбработки, "СлучайноеЗначение") > 0 Тогда
		Разница = ГенераторСлучайныхЧисел.СлучайноеЧисло(1, 730);
		Свойство = Свойство - СуткиВСекундах * Разница;
	Иначе
		Обработано = Ложь;
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбработатьХранилищеЗначений(Свойство, ПараметрыСвойства, Обработано)
	
	ПравилоОбработки = ПравилоХранилищеЗначений;
	Если ПараметрыСвойства.ПравилоОбработки.Количество() > 0 Тогда
		ПараметрыОбработкиХранилищаЗначений = ПараметрыСвойства.ПравилоОбработки.НайтиПоЗначению("Булево");
		Если ПараметрыОбработкиХранилищаЗначений <> Неопределено Тогда
			ПравилоОбработки = ПараметрыОбработкиХранилищаЗначений.Представление;
		КонецЕсли;
	КонецЕсли;
	
	Если ПравилоОбработки = "Очистить" Тогда
		Свойство = Неопределено;
	Иначе
		Обработано = Ложь;
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗаписатьДанные(Знач Данные, Знач РегистрироватьНаУзлахПлановОбмена = Ложь, Знач ВключитьБизнесЛогику = Ложь)
	
	Данные.ОбменДанными.Загрузка = Не ВключитьБизнесЛогику;
	Данные.ДополнительныеСвойства.Вставить("СкрытиеКонфиденциальнойИнформации");
	
	Если Не РегистрироватьНаУзлахПлановОбмена Тогда
		Данные.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов");
		Данные.ОбменДанными.Получатели.АвтоЗаполнение = Ложь;
	КонецЕсли;
	
	Данные.Записать();
	
КонецПроцедуры

Функция ОбщийМодуль(Имя)
	
	Если Метаданные.ОбщиеМодули.Найти(Имя) <> Неопределено Тогда
		// АПК:488-выкл ВычислитьВБезопасномРежиме не используется, чтобы избежать вызова ОбщийМодуль рекурсивно.
		УстановитьБезопасныйРежим(Истина);
		Модуль = Вычислить(Имя);
		// АПК:488-вкл
	Иначе
		Модуль = Неопределено;
	КонецЕсли;
	
	Возврат Модуль;
	
КонецФункции

#КонецОбласти

#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли